/* USER CODE BEGIN Header */
/**
  ******************************************************************************
  * @file           : main.c
  * @brief          : Main program body
  ******************************************************************************
  * @attention
  *
  * <h2><center>&copy; Copyright (c) 2021 STMicroelectronics.
  * All rights reserved.</center></h2>
  *
  * This software component is licensed by ST under BSD 3-Clause license,
  * the "License"; You may not use this file except in compliance with the
  * License. You may obtain a copy of the License at:
  *                        opensource.org/licenses/BSD-3-Clause
  *
  ******************************************************************************
  */
/* USER CODE END Header */
/* Includes ------------------------------------------------------------------*/
#include "main.h"
#include "spi.h"
#include "tim.h"
#include "usart.h"
#include "gpio.h"
#include "filter.h"
#include "mpu6500.h"
#include "string.h"

/* Private includes ----------------------------------------------------------*/
/* USER CODE BEGIN Includes */

/* USER CODE END Includes */

/* Private typedef -----------------------------------------------------------*/
/* USER CODE BEGIN PTD */

/* USER CODE END PTD */

/* Private define ------------------------------------------------------------*/
/* USER CODE BEGIN PD */
#define LED_MODE_NUM	5
#define STOP_MODE		6
#define LEFT_MODE		7
#define RIGHT_MODE	8

#define OFF_MODE			 0
#define ON_MODE				 1
#define BREATHING_MODE 2
#define BLINKING_MODE  3
#define WATERFALL_MODE 4


#define IDLE	 0
#define STOP	 1
#define LEFT	 2
#define RIGHT	 3

#define MAX		50
#define MIN		0

#define _10MS		25
#define _500MS	1250
#define _100MS	250

#define UP  	0
#define DOWN 	1

/* USER CODE END PD */

/* Private macro -------------------------------------------------------------*/
/* USER CODE BEGIN PM */

/* USER CODE END PM */

/* Private variables ---------------------------------------------------------*/

/* USER CODE BEGIN PV */
uint16_t event_500ms = 0;
uint16_t event_100ms = 0;
uint8_t event_10ms = 0;
uint8_t pwm_step = 0;
uint8_t led_mode = 0;
uint8_t tmp_mode = 0;
uint8_t LED[12][2];
uint8_t tmp_LED[12][2];
uint8_t cnt_mode = 0;
uint8_t flow_mode = 0;

uint8_t flg_10ms = 1;
uint8_t flg_500ms = 0;
uint8_t flg_100ms = 0;

extern Mpu_data_t mpu_data;
extern Mpu_filter_data_t mpu_filter_data;
/* USER CODE END PV */

/* Private function prototypes -----------------------------------------------*/
void SystemClock_Config(void);
/* USER CODE BEGIN PFP */

/* USER CODE END PFP */
void LED_change_mode();
/* Private user code ---------------------------------------------------------*/
/* USER CODE BEGIN 0 */

/* USER CODE END 0 */

/**
  * @brief  The application entry point.
  * @retval int
  */
int main(void)
{
  /* USER CODE BEGIN 1 */

  /* USER CODE END 1 */

  /* MCU Configuration--------------------------------------------------------*/

  /* Reset of all peripherals, Initializes the Flash interface and the Systick. */
  HAL_Init();

  /* USER CODE BEGIN Init */

  /* USER CODE END Init */

  /* Configure the system clock */
  SystemClock_Config();

  /* USER CODE BEGIN SysInit */

  /* USER CODE END SysInit */

  /* Initialize all configured peripherals */
  MX_GPIO_Init();
  MX_SPI1_Init();
  //MX_USART1_UART_Init();
  MX_TIM2_Init();
  /* USER CODE BEGIN 2 */
	mpu6500_init();
  /* USER CODE END 2 */

  /* Infinite loop */
  /* USER CODE BEGIN WHILE */
	
	//printf("test\n");
	while (MPU_SPI_Check() != 0x70){
		HAL_Delay(50);
	}

	LED_change_mode();
	
	HAL_TIM_Base_Start_IT(&htim2);
  while (1)
  {
			
    /* USER CODE END WHILE */
		;
    /* USER CODE BEGIN 3 */
  }
  /* USER CODE END 3 */
}

void LED_PWMout(){
	GPIOA->ODR =  (GPIOA->ODR & (~(LED_R0_Pin | LED_R1_Pin | LED_R2_Pin))) | \
								((~(LED[11][0]  &  (LED[11][1]  >  pwm_step)) << 12 )  &  LED_R0_Pin) | \
								((~(LED[10][0]  &  (LED[10][1]  >  pwm_step)) << 11 )  &  LED_R1_Pin) | \
								((~(LED[9][0]  &  (LED[9][1]  >  pwm_step)) << 8  )  &  LED_R2_Pin);
	
	GPIOB->ODR = (GPIOB->ODR & (~(LED_R3_Pin | LED_R4_Pin | LED_R5_Pin | LED_L0_Pin | LED_L1_Pin | LED_L2_Pin | LED_L3_Pin | LED_L4_Pin | LED_L5_Pin))) | \
								((~(LED[0][0]  &  (LED[0][1]  >  pwm_step)) << 0  )  &  LED_L0_Pin) | \
								((~(LED[1][0]  &  (LED[1][1]  >  pwm_step)) << 1  )  &  LED_L1_Pin) | \
								((~(LED[2][0]  &  (LED[2][1]  >  pwm_step)) << 2  )  &  LED_L2_Pin) | \
								((~(LED[3][0]  &  (LED[3][1]  >  pwm_step)) << 10 )  &  LED_L3_Pin) | \
								((~(LED[4][0]  &  (LED[4][1]  >  pwm_step)) << 11 )  &  LED_L4_Pin) | \
								((~(LED[5][0]  &  (LED[5][1]  >  pwm_step)) << 12 )  &  LED_L5_Pin) | \
								((~(LED[8][0]  &  (LED[8][1]  >  pwm_step)) << 15 )  &  LED_R3_Pin) | \
								((~(LED[7][0] &  (LED[7][1] >  pwm_step)) << 14 )  &  LED_R4_Pin) | \
								((~(LED[6][0] &  (LED[6][1] >  pwm_step)) << 13 )  &  LED_R5_Pin);
}

uint8_t process_data(){
	mpu_read_raw();
	mpu_average_filter();
	return get_status();
}

void LED_PEAK(){
	for( int i = 0; i < 12; i++){
		LED[i][0] = 1;
		LED[i][1] = MAX;
	}
}

void LED_LEFT(){
	for( int i = 5; i >= 0; i--){
		if (LED[i][0] == 1)
			continue;
		else {
			LED[i][0] = 1;
			LED[i][1] = MAX;
			return;
		}
	}
}


void LED_RIGHT(){
	for( int i = 6; i < 12; i++){
		if (LED[i][0])
			continue;
		else {
			LED[i][0] = 1;
			LED[i][1] = MAX;
			return;
		}
	}
}


void process_10ms(){
	switch (process_data()){
		case IDLE:
			
			break;
			
		case STOP:
			memcpy(tmp_LED, LED, sizeof(LED));
			memset(LED, 0, sizeof(LED));
			tmp_mode = led_mode;
			led_mode = STOP_MODE;
			LED_PEAK();
			flg_10ms = 0;
		  flg_100ms = 1;
		  flg_500ms = 1;
			event_500ms = 0;
			event_100ms = 0;
			break;
				
		case LEFT:
			memcpy(tmp_LED, LED, sizeof(LED));
			memset(LED, 0, sizeof(LED));
			tmp_mode = led_mode;
			led_mode = LEFT_MODE;
			LED_LEFT();
			flg_10ms = 0;
		  flg_100ms = 1;
		  flg_500ms = 1;
			event_500ms = 0;
			event_100ms = 0;
			break;
				
		case RIGHT:
			memcpy(tmp_LED, LED, sizeof(LED));
			memset(LED, 0, sizeof(LED));
			tmp_mode = led_mode;
			led_mode = RIGHT_MODE;
			LED_RIGHT();
			flg_10ms = 0;
		  flg_100ms = 1;
		  flg_500ms = 1;
			event_500ms = 0;
			event_100ms = 0;
			break;
					
	}
	event_10ms = 0;
}

void LED_change_mode(){
	switch (led_mode){
		case OFF_MODE:
			flg_100ms = 0;
			flg_500ms = 0;
			for (int i = 0; i < 12; i++){
				LED[i][0] = 0;
			}
			break;
			
		case ON_MODE:
			for (int i = 0; i < 12; i++){
				LED[i][0] = 1;
				LED[i][1] = 15;
			}
			break;
			
		case BREATHING_MODE:
			cnt_mode = UP;
			flg_100ms = 1;
			flg_500ms = 0;
			for (int i = 0; i < 12; i++){
				LED[i][0] = 1;
				LED[i][1] = 0;
			}
			break;
			
		case BLINKING_MODE:
			flg_100ms = 0;
			flg_500ms = 1;
			for (int i = 0; i < 12; i++){
				LED[i][0] = 1;
				LED[i][1] = 25;
			}
			break;
			
		case WATERFALL_MODE:
			flow_mode = 0;
			flg_100ms = 1;
			flg_500ms = 0;
			for (int i = 0; i < 12; i++){
				LED[i][0] = 0;
				LED[i][1] = 25;
			}
		
			break;
	}
}

void rst_led_mode(){
	memcpy(LED, tmp_LED, sizeof(LED));
	led_mode = tmp_mode;
	flg_10ms = 1;
	flg_100ms = 0;
	flg_500ms = 0;
	event_10ms = _10MS; 
	event_500ms = 0;
	event_100ms = 0;
	LED_change_mode();
}



void process_100ms(){
	switch (led_mode){
		case STOP_MODE:
			;
			break;
		
		case LEFT_MODE:
			LED_LEFT();
			break;
		
		case RIGHT_MODE:
			LED_RIGHT();
			break;
		
		case BREATHING_MODE:
			for (int i = 0; i < 12; i++){
				if (cnt_mode == UP)
				  LED[i][1] += 3;
				else
					LED[i][1] -= 3;
			}
			if (LED[0][1] <= 5)
				cnt_mode = UP;
			if (LED[0][1] >= 50)
				cnt_mode = DOWN;
			break;
			
		case WATERFALL_MODE:
			switch (flow_mode){
				int i = 0;
				case 0:
					for( i = 0; i < 12; i++){
						if (LED[i][0] == 1)
							continue;
						else {
							LED[i][0] = 1;
							break;
						}
					}
					if (i >= 11)
						flow_mode = 1;
					break;
				
				case 1:
					for( i = 11; i >= 0; i--){
						if (LED[i][0] == 0)
							continue;
						else {
							LED[i][0] = 0;
							break;
						}
					}
					if (i <= 0)
						flow_mode = 2;
					break;
				
				case 2:
					for( i = 11; i >= 0; i--){
						if (LED[i][0] == 1)
							continue;
						else {
							LED[i][0] = 1;
							break;
						}
					}
					if (i <= 0)
						flow_mode = 3;
					
					break;
				
				case 3:
					for( i = 0; i < 12; i++){
						if (LED[i][0] == 0)
							continue;
						else {
							LED[i][0] = 0;
							break;
						}
					}
					if (i >= 11)
						flow_mode = 4;
					break;
				
				case 4:
					for( i = 0; i < 6; i++){
						if (LED[i][0] == 1)
							continue;
						else {
							LED[i][0] = 1;
							LED[11 - i][0] = 1;
							break;
						}
					}
					if (i >= 6)
						flow_mode = 5;
					break;
				
				case 5:
					for( i = 5; i >= 0; i--){
						if (LED[i][0] == 0)
							continue;
						else {
							LED[i][0] = 0;
							LED[11 - i][0] = 0;
							break;
						}
					}
					if (i <= 0)
						flow_mode = 6;
					break;
				
				case 6:
					for( i = 5; i >= 0; i--){
						if (LED[i][0] == 1)
							continue;
						else {
							LED[i][0] = 1;
							LED[11 - i][0] = 1;
							break;
						}
					}
					if (i <= 0)
						flow_mode = 7;
					
					break;
				
				case 7:
					for( i = 0; i < 12; i++){
						if (LED[i][0] == 0)
							continue;
						else {
							LED[i][0] = 0;
							LED[11 - i][0] = 0;
							break;
						}
					}
					if (i >= 6)
						flow_mode = 0;
					break;
			}
	}
	event_100ms = 0;
}


void process_500ms(){
	switch (led_mode){
		case STOP_MODE:
			rst_led_mode();
			break;
		
		case LEFT_MODE:
			rst_led_mode();
			break;
		
		case RIGHT_MODE:
			rst_led_mode();
			break;
		
		case BLINKING_MODE:
			for (int i = 0; i < 12; i++){
				LED[i][0] = !LED[i][0];
				LED[i][1] = 25;
			}
			event_500ms = 0;
			break;
	}
}


void process_LED(){
	LED_PWMout();
	if(pwm_step++ > MAX)
		pwm_step = MIN;
}

void HAL_TIM_PeriodElapsedCallback(TIM_HandleTypeDef *htim){
	if (htim == (&htim2)){
		
		process_LED();
		
		if ((event_500ms >= _500MS) & flg_500ms){
			process_500ms();
		}
		
		if ((event_100ms >= _100MS) & flg_100ms){
			process_100ms();
		}
		
		if ((event_10ms >= _10MS) & flg_10ms){
			process_10ms();
		}

		if (flg_10ms)
			event_10ms++;
		if (flg_100ms)
			event_100ms++;
		if (flg_500ms)
			event_500ms++;
	}
}

void HAL_GPIO_EXTI_Callback(uint16_t GPIO_Pin){
	if (GPIO_Pin == (Key_Pin)){
		HAL_Delay(5);
		if (HAL_GPIO_ReadPin(Key_GPIO_Port, Key_Pin)){
			if (led_mode < 6)
				led_mode++;
			while (HAL_GPIO_ReadPin(Key_GPIO_Port, Key_Pin)){
				HAL_Delay(5);
			}
		}
		LED_change_mode();
		if (led_mode == LED_MODE_NUM){
			led_mode = 0;
		}
	}
}

/**
  * @brief System Clock Configuration
  * @retval None
  */
void SystemClock_Config(void)
{
  RCC_OscInitTypeDef RCC_OscInitStruct = {0};
  RCC_ClkInitTypeDef RCC_ClkInitStruct = {0};

  /** Initializes the RCC Oscillators according to the specified parameters
  * in the RCC_OscInitTypeDef structure.
  */
  RCC_OscInitStruct.OscillatorType = RCC_OSCILLATORTYPE_HSE;
  RCC_OscInitStruct.HSEState = RCC_HSE_ON;
  RCC_OscInitStruct.HSEPredivValue = RCC_HSE_PREDIV_DIV1;
  RCC_OscInitStruct.HSIState = RCC_HSI_ON;
  RCC_OscInitStruct.PLL.PLLState = RCC_PLL_ON;
  RCC_OscInitStruct.PLL.PLLSource = RCC_PLLSOURCE_HSE;
  RCC_OscInitStruct.PLL.PLLMUL = RCC_PLL_MUL9;
  if (HAL_RCC_OscConfig(&RCC_OscInitStruct) != HAL_OK)
  {
    Error_Handler();
  }
  /** Initializes the CPU, AHB and APB buses clocks
  */
  RCC_ClkInitStruct.ClockType = RCC_CLOCKTYPE_HCLK|RCC_CLOCKTYPE_SYSCLK
                              |RCC_CLOCKTYPE_PCLK1|RCC_CLOCKTYPE_PCLK2;
  RCC_ClkInitStruct.SYSCLKSource = RCC_SYSCLKSOURCE_PLLCLK;
  RCC_ClkInitStruct.AHBCLKDivider = RCC_SYSCLK_DIV1;
  RCC_ClkInitStruct.APB1CLKDivider = RCC_HCLK_DIV2;
  RCC_ClkInitStruct.APB2CLKDivider = RCC_HCLK_DIV1;

  if (HAL_RCC_ClockConfig(&RCC_ClkInitStruct, FLASH_LATENCY_2) != HAL_OK)
  {
    Error_Handler();
  }
}

/* USER CODE BEGIN 4 */

/* USER CODE END 4 */

/**
  * @brief  This function is executed in case of error occurrence.
  * @retval None
  */
void Error_Handler(void)
{
  /* USER CODE BEGIN Error_Handler_Debug */
  /* User can add his own implementation to report the HAL error return state */
  __disable_irq();
  while (1)
  {
  }
  /* USER CODE END Error_Handler_Debug */
}

#ifdef  USE_FULL_ASSERT
/**
  * @brief  Reports the name of the source file and the source line number
  *         where the assert_param error has occurred.
  * @param  file: pointer to the source file name
  * @param  line: assert_param error line source number
  * @retval None
  */
void assert_failed(uint8_t *file, uint32_t line)
{
  /* USER CODE BEGIN 6 */
  /* User can add his own implementation to report the file name and line number,
     ex: printf("Wrong parameters value: file %s on line %d\r\n", file, line) */
  /* USER CODE END 6 */
}
#endif /* USE_FULL_ASSERT */

/************************ (C) COPYRIGHT STMicroelectronics *****END OF FILE****/
